package com.topisv.tms.service.stock.instorage;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.QueryParamHolder;
import com.topisv.tms.entity.stock.instorage.InstorageBill;
import com.topisv.tms.entity.stock.instorage.InstorageCountItem;
import com.topisv.tms.entity.stock.instorage.InstorageUpDispatchSubTask;
import com.topisv.tms.entity.stock.instorage.InstorageUpDispatchTask;
import com.topisv.tms.entity.stock.instorage.InstorageUpSubTaskItem;
import com.topisv.tms.entity.stock.instorage.InstorageUpTask;
import com.topisv.tms.entity.stock.instorage.InstorageUpTaskItem;
import com.topisv.tms.exception.ErrorCode;
import com.topisv.tms.exception.PaiUException;
import com.topisv.tms.repository.stock.instorage.InstorageCountItemDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpDispatchSubTaskDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpDispatchSubTaskItemDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpDispatchTaskDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpTaskDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpTaskItemDao;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.service.vo.PrinterStyleType;
import com.topisv.tms.utils.EdiOrderUtil;
import com.topisv.tms.utils.PrintModelUtil;
import com.topisv.tms.utils.enums.InstorageStatusEnums;
import com.topisv.tms.utils.rule.TMSTransportRule;

@Component
@Transactional(readOnly = true)
public class InstorageUpDispatchTaskService extends BaseService {
	private static final Logger logger = LoggerFactory.getLogger(InstorageUpDispatchTaskService.class);

	@Autowired
	private InstorageUpDispatchTaskDao instorageUpDispatchTaskDao;
	@Autowired
	private InstorageUpDispatchSubTaskDao instorageUpDispatchSubTaskDao;
	@Autowired
	private InstorageUpDispatchSubTaskItemDao instorageUpDispatchSubTaskItemDao;
	@Autowired
	private InstorageCountItemDao instorageCountItemDao;
	@Autowired
	private InstorageUpTaskDao instorageUpTaskDao;
	@Autowired
	private InstorageUpTaskItemDao instorageUpTaskItemDao;

	public Page<InstorageUpDispatchTask> findCusStock(QueryParamHolder paramHolder) {
		return findByJson(paramHolder, instorageUpDispatchTaskDao, InstorageUpDispatchTask.class);
	}

	public List<InstorageUpDispatchSubTask> findByTaskCode(String taskCode) {
		return instorageUpDispatchSubTaskDao.findByTaskCode(taskCode);
	}

	public List<InstorageUpSubTaskItem> findBySubTaskCode(String subTaskCode) {
		return instorageUpDispatchSubTaskItemDao.findBySubTaskCode(subTaskCode);
	}

	public Page<InstorageUpDispatchTask> findDisPatchTask(QueryParamHolder paramHolder) {
		return findByJson(paramHolder, instorageUpDispatchTaskDao, InstorageUpDispatchTask.class);
	}

	/**
	 * 查找未分配任务的商品
	 * @param taskCode
	 * @return List<InstorageCountItem>
	 */
	public List<InstorageCountItem> unDispatchItem(String taskCode) {
		InstorageUpDispatchTask disTask = instorageUpDispatchTaskDao.findByTaskCode(taskCode);
		InstorageBill instorageBill = disTask.getInstorageBill();
		List<InstorageCountItem> countItems = instorageCountItemDao.loadByBillCode(instorageBill.getBillCode());
		Map<String, Integer> countMap = EdiOrderUtil.countNew(countItems);
		List<InstorageUpSubTaskItem> subTaskItems = instorageUpDispatchSubTaskItemDao.findByTaskCode(taskCode);
		Map<String, Integer> upTaskItems = EdiOrderUtil.countUpTaskItemNew(subTaskItems);

		List<InstorageCountItem> rs = new ArrayList<InstorageCountItem>();
		/*for (Map.Entry<String, Integer> entry : countMap.entrySet()) {
			String [] sku_error = entry.getKey().split("_");
			String sku = entry.getKey();
			String errorflag = sku_error[1];
			Integer num = entry.getValue();
			InstorageCountItem item = new InstorageCountItem();
			item.setSku(sku);
			item.setNum(num);
			item.setErrorFlag(errorflag);
			Integer upNum = upTaskItems.get(sku);
			item.setUpNum(upNum == null ? 0 : upNum);
			rs.add(item);
		}*/
		
		for (String key: countMap.keySet()) {
		    String[] keyList = key.split("_",-1);
            InstorageCountItem item = new InstorageCountItem();
            item.setSku(keyList[0]);
            item.setBatchCode(keyList[1]);
            item.setProductDate(keyList[2]);
            item.setExpireDate(keyList[3]);
            item.setNum(countMap.get(key));
            item.setErrorFlag(keyList[4]);
            Integer upNum = upTaskItems.get(key);
            item.setUpNum(upNum == null ? 0 : upNum);
            rs.add(item);
        }
		
		Collections.sort(rs, new Comparator<InstorageCountItem>() {
			@Override
			public int compare(InstorageCountItem o1, InstorageCountItem o2) {
				return (o2.getNum() - o2.getUpNum()) == 0 ? -1 : (o1.getNum() - o1.getUpNum()) == 0 ? 1 : (Integer.compare(o1.getNum() - o1.getUpNum(), o2.getNum() - o2.getUpNum()));
			}

		});
		return rs;
	}

	/**
	 * 查询点收任务
	 * @param param
	 * @return
	 */
	public List<InstorageUpDispatchTask> loadTaskByParam(Map<String, Object> param) {
		Specification<InstorageUpDispatchTask> spec = getWhereClause(param);
		List<InstorageUpDispatchTask> taskList = this.instorageUpDispatchTaskDao.findAll(spec);
		return taskList;
	}

	private Specification<InstorageUpDispatchTask> getWhereClause(final Map<String, Object> param) {
		return new Specification<InstorageUpDispatchTask>() {
			@Override
			public Predicate toPredicate(Root<InstorageUpDispatchTask> r, CriteriaQuery<?> q, CriteriaBuilder cb) {
				Predicate pre = cb.conjunction();

				// 商家组
				String customerCodes = (String) param.get("customerCodes");
				if (StringUtils.isNotBlank(customerCodes)) {
					String[] customerCodeSplit = customerCodes.split(":");
					ComparisonPredicate[] tempCustomerCode = new ComparisonPredicate[customerCodeSplit.length];
					int i = 0;
					for (String _customerCode : customerCodeSplit) {
						tempCustomerCode[i] = (ComparisonPredicate) cb.equal(r.get("instorageBill").get("customerCode"), _customerCode);
						i++;
					}
					pre.getExpressions().add(cb.or(tempCustomerCode));
				}

				// 仓库组
				String areagroups = (String) param.get("areagroups");
				if (StringUtils.isNotBlank(areagroups)) {
					String[] areagroupSplit = areagroups.split(":");
					ComparisonPredicate[] areagroupArray = new ComparisonPredicate[areagroupSplit.length];
					int j = 0;
					for (String _areagroup : areagroupSplit) {
						areagroupArray[j] = (ComparisonPredicate) cb.equal(r.get("instorageBill").get("inwarehouseCode"), _areagroup);
						j++;
					}
					pre.getExpressions().add(cb.or(areagroupArray));
				}

				// 状态
				String status = (String) param.get("status");
				if (StringUtils.isNotEmpty(status)) {
					pre.getExpressions().add(cb.equal(r.get("status"), status));
				}

				// 作业员
				if (param.get("workerUuid") != null) {
					String workerUuid = (String) param.get("workerUuid");
					pre.getExpressions().add(cb.equal(r.get("workerUuid"), workerUuid));
				}

				return pre;
			}
		};
	}

	/**
	 * 领取任务
	 * @param taskId 任务ID
	 * @param jobuuid 任务执行人
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public String takeTask(Long taskId, String jobuuid) throws Exception {

		try {
			InstorageUpDispatchTask task = this.instorageUpDispatchTaskDao.findOne(taskId);
			//add LiBin 20160829 防止重复领取任务
			if ("2".equals(task.getStatus())) {
			    throw new PaiUException(ErrorCode.REDO_INSTORAGE_UP_DISPATCH_TASK); 
            }
			if ("1".equals(task.getStatus())) {
                throw new PaiUException(ErrorCode.REDO1_INSTORAGE_UP_DISPATCH_TASK); 
            }
			InstorageBill bill = task.getInstorageBill();
			// 已取消的不能领取
			if (InstorageStatusEnums.CANCEL.getType().equals(bill.getStatus())) {
				throw new PaiUException(ErrorCode.ORDER_CANCELED_ERROR, new String[] { bill.getBillCode() });
			}
			// 修改任务状态
			task.setWorkerUuid(jobuuid);
			task.setStatus("1"); // 任务状态 （undo.创建点收任务 token:领取任务 doing:点收中
			this.instorageUpDispatchTaskDao.save(task);
			return "success";
		} catch (Exception e) {
			//throw new Exception(e);//update LiBin 20160829 
		    throw e;
		}
	}

	public InstorageUpDispatchTask findOne(Long id) {
		return instorageUpDispatchTaskDao.findOne(id);
	}

	/**
	 * 创建子任务
	 * @param taskCode 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public InstorageUpDispatchSubTask createSubTask(String taskCode) {
		InstorageUpDispatchSubTask subTask = new InstorageUpDispatchSubTask();
		subTask.setSubTaskCode(TMSTransportRule.generateDispatchSubTaskCode());
		subTask.setTaskCode(taskCode);
		logger.info("createSubTask--生成子任务号--taskCode:"+taskCode+"--subTaskCode"+subTask.getSubTaskCode());
		return instorageUpDispatchSubTaskDao.save(subTask);
	}

	/**
	 * 更新子任务明细
	 * @param item
	 * @param subTaskCode void
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void updateSubDetail(InstorageUpSubTaskItem[] item, String taskCode, String subTaskCode) {
		//移除数量为0的商品行
		List<InstorageUpSubTaskItem> list = new ArrayList<InstorageUpSubTaskItem>();
		for(InstorageUpSubTaskItem instorageUpSubTaskItem:item){
			list.add(instorageUpSubTaskItem) ;
		}
		for(int i = 0;i<list.size();i++){
			if(list.get(i).getNum() == 0){
				list.remove(i) ;
				i-- ;
			}
		}
		InstorageUpSubTaskItem item2[] = new InstorageUpSubTaskItem[list.size()] ;
		for(int i = 0;i<list.size();i++){
			item2[i] = list.get(i) ;
		}
		// 子任务单号为空时，新增
		logger.info("updateSubDetail--开始更新子任务明细--taskCode:"+taskCode+"--subTaskCode"+subTaskCode);
		if (StringUtils.isBlank(subTaskCode)) {
			if (item2.length > 0) {
				InstorageUpDispatchSubTask subTask = createSubTask(taskCode);
				logger.info("updateSubDetail--生成子任务号--taskCode:"+taskCode+"--subTaskCode"+subTask.getSubTaskCode()+"--"+item2.length);
				for (InstorageUpSubTaskItem instorageUpSubTaskItem : item2) {
					instorageUpSubTaskItem.setSubTaskCode(subTask.getSubTaskCode());
				}
				instorageUpDispatchSubTaskItemDao.save(Arrays.asList(item2));
			}
		} else {
			if (item2.length == 0) {
				instorageUpDispatchSubTaskDao.deleteBySubTaskCode(subTaskCode);
			}
			instorageUpDispatchSubTaskItemDao.deleteBySubTaskCode(subTaskCode);
			instorageUpDispatchSubTaskItemDao.save(Arrays.asList(item2));
		}
	}
	
	/**
	 * 校验数量，避免出现负数量
	 * @param item
	 * @param taskCode
	 */
	public boolean checkNum(InstorageUpSubTaskItem[] item, String taskCode,String billCode,String subTaskCode){
		Map<String, String> stItem = new HashMap<String, String>() ; 
		boolean flag = true ; 
		for(InstorageUpSubTaskItem instorageUpSubTaskItem:item){//循环提交的明细
			/*String nowSku = instorageUpSubTaskItem.getSkuCode();*/
			//bug190 by zhangweize L270
		    
		    /** begin modify 20161103 bug:304 暂时移除批次逻辑(存在bug) */
			/*String nowSku = instorageUpSubTaskItem.getSkuCode()+"_"+instorageUpSubTaskItem.getErrorFlag()+"_"+
			    instorageUpSubTaskItem.getBatchCode()+"_"+instorageUpSubTaskItem.getProductDate()+"_"+
			    instorageUpSubTaskItem.getExpireDate();*/
			String nowSku = instorageUpSubTaskItem.getSkuCode()+"_"+instorageUpSubTaskItem.getErrorFlag();
			/** end modify 20161103 bug:304 暂时移除批次逻辑(存在bug) */
			
			if(stItem.containsKey(nowSku)){
				String num = String
						.valueOf(Integer.parseInt((String) stItem.get(nowSku)) + instorageUpSubTaskItem.getNum());
				stItem.put(nowSku,num) ; 
			}else{
				stItem.put(nowSku,String.valueOf(instorageUpSubTaskItem.getNum())) ; 
			}
		}
		if(StringUtils.isBlank(subTaskCode)){
			List<InstorageUpSubTaskItem> stItem2 = instorageUpDispatchSubTaskItemDao.findByTaskCode(taskCode) ; //循环已存在的明细
			for(InstorageUpSubTaskItem instorageUpSubTaskItem:stItem2){//循环提交的明细
//				String nowSku = instorageUpSubTaskItem.getSkuCode() ;
				//bug190 by zhangweize L283
			    
			    /** begin modify 20161103 bug:304 暂时移除批次逻辑(存在bug) */
				/*String nowSku = instorageUpSubTaskItem.getSkuCode()+"_"+instorageUpSubTaskItem.getErrorFlag()+"_"+
				    instorageUpSubTaskItem.getBatchCode()+"_"+instorageUpSubTaskItem.getProductDate()+"_"+
	                instorageUpSubTaskItem.getExpireDate();*/
				String nowSku = instorageUpSubTaskItem.getSkuCode()+"_"+instorageUpSubTaskItem.getErrorFlag();
				/** end modify 20161103 bug:304 暂时移除批次逻辑(存在bug) */
				
				if(stItem.containsKey(nowSku)){
					String num = String.valueOf(Integer.parseInt((String) stItem.get(nowSku)) + instorageUpSubTaskItem.getNum());
					stItem.put(nowSku,num) ; 
				}else{
					stItem.put(nowSku,String.valueOf(instorageUpSubTaskItem.getNum())) ; 
				}
			}
		}
		List<InstorageCountItem> itemAll = instorageCountItemDao.loadByBillCode(billCode);
		for(InstorageCountItem instorageCountItem:itemAll){
			//bug190 by zhangweize L295-L296
		    
		    /** begin modify 20161103 bug:304 暂时移除批次逻辑 */
			/*if (stItem.containsKey((instorageCountItem.getSku() + "_" + instorageCountItem.getErrorFlag()+"_"+instorageCountItem.getBatchCode()+
			    "_"+instorageCountItem.getProductDate()+"_"+instorageCountItem.getExpireDate()))) {
				if (instorageCountItem.getNum() < Integer.parseInt(
						(String) stItem.get(instorageCountItem.getSku() + "_" + instorageCountItem.getErrorFlag()+"_"+instorageCountItem.getBatchCode()+
			                "_"+instorageCountItem.getProductDate()+"_"+instorageCountItem.getExpireDate()))) {
					flag = false ; 
					break ; 
				}
			}*/
		    if (stItem.containsKey((instorageCountItem.getSku() + "_" + instorageCountItem.getErrorFlag()))) {
				if (instorageCountItem.getNum() < Integer.parseInt((String) stItem.get(instorageCountItem.getSku() + "_" + instorageCountItem.getErrorFlag()))) {
					flag = false ;
					break ; 
				}
			}
			/** end modify 20161103 bug:304 暂时移除批次逻辑(存在bug) */
		}
		return flag;
	}

	/**
	 * 删除子任务
	 * @param subTaskCode 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void deleteSubTask(String subTaskCode) {
		instorageUpDispatchSubTaskDao.deleteBySubTaskCode(subTaskCode);
		instorageUpDispatchSubTaskItemDao.deleteBySubTaskCode(subTaskCode);
	}

	/**
	 * 完成任务分配
	 * @param taskId 
	 */
	@Transactional(readOnly = false, rollbackFor = Exception.class)
	public void finishDispatchTask(Long taskId) {
		Date now = new Date();
		InstorageUpDispatchTask instorageUpDispatchTask = instorageUpDispatchTaskDao.findOne(taskId);
		if("2".equals(instorageUpDispatchTask.getStatus())){
			return;
		}
		instorageUpDispatchTask.setStatus("2");
		instorageUpDispatchTaskDao.save(instorageUpDispatchTask);

		// 完成分配 生成上架任务
		InstorageBill instorageBill = instorageUpDispatchTask.getInstorageBill();
		List<InstorageCountItem> items = instorageCountItemDao.loadByBillCode(instorageBill.getBillCode());
		if (items.size() > 0) {
			List<InstorageUpDispatchSubTask> upDispatchSubTasks =  instorageUpDispatchSubTaskDao.findByTaskCode(instorageUpDispatchTask.getTaskCode());
			for(InstorageUpDispatchSubTask subTask : upDispatchSubTasks){
				InstorageUpTask upTask = new InstorageUpTask();
				upTask.setBillCode(instorageBill.getBillCode());
				upTask.setCreateTime(now);
				upTask.setCustomerCode(instorageBill.getCustomerCode());
				upTask.setSubTaskCode(subTask.getSubTaskCode());
				upTask.setStatus("undo");
				upTask.setTaskCode(TMSTransportRule.generateUpTaskCode());
				upTask.setTaskType("box");
				upTask.setWarehouseCode(instorageBill.getInwarehouseCode());
				upTask.setErrorFlag(instorageBill.getErrorFlag());
				instorageUpTaskDao.save(upTask);

		/*		for (InstorageCountItem item : items) {
					item.setUptaskCode(upTask.getTaskCode());
				}
				this.instorageCountItemDao.save(items);*/
			}
		}
	}

	public List<PrinterStyleType> printUpTask(String taskCode) {
		List<PrinterStyleType> rs = new ArrayList<PrinterStyleType>();
		List<InstorageUpDispatchSubTask> subTasks = instorageUpDispatchSubTaskDao.findByTaskCode(taskCode);
		for (InstorageUpDispatchSubTask subTask : subTasks) {
			List<InstorageUpSubTaskItem> items = instorageUpDispatchSubTaskItemDao.findBySubTaskCode(subTask.getSubTaskCode());
			String content = PrintModelUtil.buildUpTaskPrintContent(items);
			PrinterStyleType style = new PrinterStyleType();
			style.setContent(content);
			style.setPrinterName(subTask.getSubTaskCode());
			rs.add(style);
		}
		return rs;
	}
	
	/**
	 * 查找未上架任务的商品
	 * @param taskCode
	 * @return List<InstorageCountItem>
	 */
	public List<InstorageUpSubTaskItem> unUpDispatchItem(String taskCode) {
		InstorageUpTask upTask = instorageUpTaskDao.loadByTaskCode(taskCode);
		List<InstorageUpSubTaskItem> countItems = instorageUpDispatchSubTaskItemDao.findBySubTaskCode(upTask.getSubTaskCode());
		Map<String, Integer> countMap = EdiOrderUtil.countUpTaskItemNew(countItems);
		
		List<InstorageUpTaskItem> upTaskItems = instorageUpTaskItemDao.findByUpTaskCode(taskCode);
		Map<String, Integer> upTaskItemMap = EdiOrderUtil.countInstorageUpTaskItemNew(upTaskItems);
		
		List<InstorageUpSubTaskItem> rs = new ArrayList<InstorageUpSubTaskItem>();
		/*for (Map.Entry<String, Integer> entry : countMap.entrySet()) {
			String [] sku_error = entry.getKey().split("_");
			String sku = entry.getKey();
			String errorflag = sku_error[1];
			Integer num = entry.getValue();
			InstorageUpSubTaskItem item = new InstorageUpSubTaskItem();
			item.setSkuCode(sku);
			item.setNum(num);
			item.setErrorFlag(errorflag);
			Integer upNum = upTaskItemMap.get(sku);
			item.setUpNum(upNum == null ? 0 : upNum);
			rs.add(item);
		}*/
		for (String key : countMap.keySet()) {
		    String[] strList = key.split("_",-1);
		    String sku = strList[0];
		    String batchCode = strList[1];
		    String productDate = strList[2];
		    String expireDate = strList[3];
		    String errorflag = strList[4];
            Integer num = countMap.get(key);
            InstorageUpSubTaskItem item = new InstorageUpSubTaskItem();
            item.setSkuCode(sku);
            item.setBatchCode(batchCode);
            item.setProductDate(productDate);
            item.setExpireDate(expireDate);
            item.setNum(num);
            item.setErrorFlag(errorflag);
            Integer upNum = upTaskItemMap.get(key);
            item.setUpNum(upNum == null ? 0 : upNum);
            rs.add(item);
        }
		Collections.sort(rs, new Comparator<InstorageUpSubTaskItem>() {
			@Override
			public int compare(InstorageUpSubTaskItem o1, InstorageUpSubTaskItem o2) {
				return (o2.getNum() - o2.getUpNum()) == 0 ? -1 : (o1.getNum() - o1.getUpNum()) == 0 ? 1 : (Integer.compare(o1.getNum() - o1.getUpNum(), o2.getNum() - o2.getUpNum()));
			}

		});
		return rs;
	}
}
